package com.yst.web.utils;

import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Utils for delay run
 */
public class DelayRunUtil {

    @Data
    @NoArgsConstructor
    @Accessors(chain = true)
    static class TimedRunnable{
        private long createTime;
        private long delay;
        private String name;
        private Runnable runnable;
    }

    private final static int INTERVAL=50;

    private final static int RUNNABLE_MAX_TIME=50;

    private final static List<TimedRunnable> runnableList = Collections.synchronizedList(new ArrayList<>());

    private final static Runnable runnable= () -> {
        while (!Thread.currentThread().isInterrupted()){
            if (!runnableList.isEmpty()){
                Long currentTime=System.currentTimeMillis();
                List<TimedRunnable> needRunList= runnableList.stream()
                        .filter((runnable)->currentTime-runnable.createTime>=runnable.delay)
                        .collect(Collectors.toList());
                for (TimedRunnable timedRunnable:needRunList){
                    long beginTime=System.currentTimeMillis();
                    try {
                        timedRunnable.getRunnable().run();
                    }
                    catch (Exception e){
                        e.printStackTrace();
                    }
                    long runTime=System.currentTimeMillis()-beginTime;
                    if (runTime>RUNNABLE_MAX_TIME){
                        System.out.printf("runnable '%s' run times %d ms too long,the max is %d ms\r\n",
                                timedRunnable.getName(),runTime,RUNNABLE_MAX_TIME);
                    }
                }

                runnableList.removeAll(needRunList);
            }
            try {
                Thread.sleep(INTERVAL);
            }
            catch (InterruptedException e){
                break;
            }
            catch (Exception e){
                e.printStackTrace();
            }
        }
    };

    private final static Thread coreThread;
    static {
        coreThread=new Thread(runnable);
        coreThread.start();
    }

    /**
     * Inaccurate delay actuator
     * @param name name of runnable
     * @param delay delay time，Time accuracy of 50 milliseconds
     * @param runnable runnable
     */
    public static void run(String name, long delay,Runnable runnable){
        TimedRunnable timedRunnable = new TimedRunnable().setRunnable(runnable)
                .setCreateTime(System.currentTimeMillis())
                .setDelay(delay).setName(name);
        runnableList.add(timedRunnable);
    }

    /**
     * Inaccurate delay actuator
     * @param runnable runnable
     * @param name name of runnable
     * @param delay delay time，Time accuracy of 50 milliseconds
     */
    public static void run(Runnable runnable,String name, long delay){
        TimedRunnable timedRunnable = new TimedRunnable().setRunnable(runnable)
                .setCreateTime(System.currentTimeMillis())
                .setDelay(delay).setName(name);
        runnableList.add(timedRunnable);
    }


}
